package org.webdb.webapp.picocontainer;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import javax.servlet.ServletContext;

import org.picocontainer.MutablePicoContainer;
import org.picocontainer.script.xml.XMLContainerBuilder;
import org.picocontainer.web.WebappComposer;

public class PicoXmlWebComposer implements WebappComposer {

    private static final String APP_PARENT_PARAM = "pico-parent";
    private static final String APP_SCRIPT_PARAM = "pico-application";
    private static final String DEFAULT_APP_PARENT_SCRIPT = "pico-parent.xml";
    private static final String DEFAULT_APP_SCRIPT = "pico-application.xml";
    private static final String DEFAULT_REQ_SCRIPT = "pico-request.xml";
    private static final String DEFAULT_SES_SCRIPT = "pico-session.xml";
    private static final String REQ_SCRIPT_PARAM = "pico-request";
    private static final String SES_SCRIPT_PARAM = "pico-session";
    private ServletContext servletContext = null;

    @Override
    public void composeApplication(MutablePicoContainer container,
            ServletContext servletContext) {
        this.servletContext = servletContext;
        populateContainer(
                (MutablePicoContainer) servletContext
                        .getAttribute(PicoBootstrap.PICO_PARENT_NAME),
                APP_PARENT_PARAM, DEFAULT_APP_PARENT_SCRIPT);
        populateContainer(container, APP_SCRIPT_PARAM, DEFAULT_APP_SCRIPT);
    }

    @Override
    public void composeRequest(MutablePicoContainer container) {
        populateContainer(container, REQ_SCRIPT_PARAM, DEFAULT_REQ_SCRIPT);
    }

    @Override
    public void composeSession(MutablePicoContainer container) {
        populateContainer(container, SES_SCRIPT_PARAM, DEFAULT_SES_SCRIPT);
    }

    private Reader loadReader(ServletContext servletContext,
            String scriptLocation) throws IOException {
        String scriptPath = servletContext.getRealPath("/WEB-INF/"
                .concat(scriptLocation));
        File file = new File(scriptPath);
        if (file.exists() && file.canRead())
            return new InputStreamReader(new FileInputStream(file));

        InputStream stream = Thread.currentThread().getContextClassLoader()
                .getResourceAsStream(scriptLocation);

        if (stream != null)
            return new InputStreamReader(stream);

        throw new IllegalArgumentException(scriptLocation);
    }

    private Reader loadReader(ServletContext servletContext, String scriptName,
            String defaultScript) throws IOException {
        String script = servletContext.getInitParameter(scriptName);
        if (script == null)
            script = defaultScript;

        return loadReader(servletContext, script);
    }

    private void populateContainer(MutablePicoContainer container,
            String scriptName, String defaultScriptName) {
        Reader reader = null;
        try {
            reader = loadReader(servletContext, scriptName, defaultScriptName);
        } catch (IOException e) {
            throw new RuntimeException("IO Exception in compose "
                    + container.toString(), e);
        }

        try {
            XMLContainerBuilder pcBuilder = new XMLContainerBuilder(reader,
                    Thread.currentThread().getContextClassLoader());

            pcBuilder.populateContainer(container);
        } catch (Throwable t) {
            throw new RuntimeException("Problems in compose "
                    + container.toString(), t);
        }
    }

}
